﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using wcsServo.cache;
using wcsServo.client;
using wcsServo.constant;
using wcsServo.dao;
using wcsServo.domain;
using wcsServo.entity;
using wcsServo.service;
using wcsServo.utils;

namespace wcsServo.handler
{
    public class JudgeHandler
    {
        private readonly string _unitNo;

        private Action<string, string, string> _showMessage;

        private FuncService _funcService = new FuncService();

        public JudgeHandler(string unitNo, Action<string, string, string> showMessage)
        {
            this._unitNo = unitNo;
            _showMessage = showMessage;
        }

        /// <summary>
        /// 监听所有item_event_dict缓存中的事件
        /// </summary>
        /// <param name="readNo"></param>
        public void JudgeEventByCache()
        {
            //根据unitNo获取所有ItemNo信息，对包含事件的点做事件判定
            if (!GlobalCachePool.plcItems_dict.TryGetValue(_unitNo, out List<PlcItemEntity> items))
            {
                return;
            }
            foreach (PlcItemEntity item in items)
            {
                if (string.IsNullOrEmpty(item.EVENT_NO))
                {
                    continue;
                }
                //ShowMessage("0", $"信号点[{item.ITEM_NO}]触发事件[{item.EVENT_NO}]");
                JudgeEventByItem(item.ITEM_NO);
            }
        }

        public void JudgeEventByItem(string itemNo)
        {
            if (string.IsNullOrEmpty(itemNo))
            {
                return;
            }
            //根据itemNo获取其事件链
            if (GlobalCachePool.links_event_dict.TryGetValue(itemNo, out List<EquationLinks_EVENT> links))
            {
                if (links == null || links.Count == 0)
                {
                    return;
                }
            }
            bool result = JudgeEventByLinks(links);
            if (result)
            {
                //ShowMessage("0", $"信号点[{itemNo}]触发事件成功");
                WriteByItemNo(itemNo);
            }
        }

        public bool JudgeEventByLinks(List<EquationLinks_EVENT> links)
        {
            if (links == null)
            {
                return false;
            }
            bool flag = true;
            //eventLinks可能包含多层触发链,层与层之间是或的关系,只要有一层触发成功,则认为事件触发成功

            foreach (EquationLinks_EVENT link in links)
            {
                List<Equation_EVENT> equations = link.EQUATIONS;
                foreach (Equation_EVENT equation in equations)
                {
                    if (!JudgeEventByEquation(equation))
                    {
                        flag = false;
                        break;
                    }
                    flag = true;
                }
                //如果当前层级都成功则事件判定成功(否则继续下一层判定)
                if (flag)
                {
                    break;
                }
            }
            return flag;
        }

        public bool JudgeEventByEquation(Equation_EVENT equation)
        {
            if (equation == null)
            {
                return false;
            }
            string symbol = equation.SYMBOL;
            string leftPrefix = equation.LEFT_PREFIX;
            string leftMark = equation.LEFT_MARK;
            string rigthtPrefix = equation.RIGHT_PREFIX;
            string rightMark = equation.RIGHT_MARK;
            //ShowMessage("0", $"尝试判定[{leftPrefix}].{leftMark}{symbol}[{rigthtPrefix}].{rightMark}");
            string leftValue = GetTargetItemValue(leftPrefix, leftMark);
            string rightValue = GetTargetItemValue(rigthtPrefix, rightMark);

            if (SymbolConstants.SYMBOL_EQUAL.Equals(symbol))
            {
                //符号为=,则两者值相等=>true
                if (leftValue.Equals(rightValue))
                {
                    return true;
                }
            }
            else if (SymbolConstants.SYMBOL_NO_EQUAL.Equals(symbol))
            {
                //符号为<>,则两者值不等=>true
                if (!leftValue.Equals(rightValue))
                {
                    return true;
                }
            }
            else
            {
                //不支持的符号
            }
            return false;
        }

        public string GetTargetItemValue(string prefix, string itemNo)
        {
            string value = "";
            //从PLC_ITEM中获取值
            if (SymbolConstants.FLAG_PLC.Equals(prefix))
            {
                if (GlobalCachePool.single_plcItem_dict.TryGetValue(itemNo, out PlcItemEntity item))
                {
                    value = item.ITEM_VALUE;
                }
            }
            else if (SymbolConstants.FLAG_MEM.Equals(prefix))
            {
                if (GlobalCachePool.single_memItem_dict.TryGetValue(itemNo, out MemItemEntity item))
                {
                    //考虑到数据库抓取一下
                    value = item.ITEM_VALUE;
                }
            }
            else
            {
                value = itemNo;
            }

            return value;
        }

        public void WriteByItemNo(string itemNo)
        {
            if (string.IsNullOrEmpty(itemNo))
            {
                return;
            }
            //1.获取点信号相关的事件
            if (GlobalCachePool.item_event_dict.TryGetValue(itemNo, out PlcEventEntity eva))
            {
                string callType = eva.CALL_TYPE;
                string callNo = eva.CALL_NO;
                string param = itemNo;
                string noLogCode = eva.NO_LOG_CODE;

                //1.1.CALL_TYPE=PLC
                if (SymbolConstants.CALL_TYPE_PLC.Equals(callType))
                {
                    if (!GlobalCachePool.write_event_dict.TryGetValue(itemNo, out List<Equation_EVENT> writes))
                    {
                        return;
                    }
                    if (writes == null || writes.Count == 0)
                    {
                        return;
                    }
                    foreach (Equation_EVENT equation in writes)
                    {
                        WriteByEquation(equation);
                    }
                }
                //1.2.CALL_TYPE=PROC
                if (SymbolConstants.CALL_TYPE_PROC.Equals(callType))
                {
                    //调用存储过程
                    ResultData_FUNC resultData_FUNC = _funcService.ExecFunction(callNo, param);
                    //输出触发结果
                    string code = resultData_FUNC.Code;
                    string msg = resultData_FUNC.Msg;
                    string writes = resultData_FUNC.Writes;
                    //ShowMessage(code, msg + writes);
                    //如果writes有值则写入PLC
                    if (!string.IsNullOrEmpty(writes))
                    {
                        List<Equation_EVENT> equations = EquationUtils.Write2Equations(writes);
                        foreach (Equation_EVENT equation in equations)
                        {
                            WriteByEquation(equation);
                        }
                    }
                    if (!code.Equals(noLogCode))
                    {
                        ShowMessage(code, msg + ";" + writes);
                    }
                }
            }
        }
        public void WriteByEquation(Equation_EVENT equation)
        {
            string prefix = equation.LEFT_PREFIX;
            string itemNo = equation.LEFT_MARK;
            string value = equation.RIGHT_MARK;
            //根据标签为PLC还是MEM,判断是否往判断往PLC还是往MEM写数据
            if (SymbolConstants.FLAG_PLC.Equals(prefix))
            {
                //找unitNo对应的client
                if (!GlobalCachePool.client_dict.TryGetValue(_unitNo, out ModbusClient client))
                {
                    return;
                }
                if (GlobalCachePool.single_plcItem_dict.TryGetValue(itemNo, out PlcItemEntity item))
                {
                    int addr = item.ITEM_ADR;
                    int len = item.DATA_LEN;
                    string typ = item.DISPLAY_TYPE;
                    ushort[] data = MyHexUtils.SetString(value, len, typ);
                    ShowMessage("0", $"向{_unitNo}设备的点[{itemNo}]写入值{value}");
                    client.WriteData(addr, data);
                }
            }
            else
            {
                //MEM的点直接更新内存中的数据即可
                if (GlobalCachePool.single_memItem_dict.TryGetValue(itemNo, out MemItemEntity mem))
                {
                    mem.OLD_VALUE = mem.ITEM_VALUE;
                    mem.ITEM_VALUE = value;
                    mem.UPDATE_DATE = DateTime.Now;
                    GlobalCachePool.single_memItem_dict[itemNo] = mem;
                    //同时更新mem_item表中的值
                    DBFactory.UpdateMemByItemNo(mem);
                }
            }
        }

        public void ShowMessage(string code, string msg)
        {
            _showMessage?.Invoke(_unitNo, code, msg);
        }
    }
}
